#include "snake.h"
#include "networking.h"
#include "point.h"
#include "graphics.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char getNextSnakeChar()
{
	return cNextSnakeChar++;
}

Snake* initSnake(Point point, char cSnakeChar)
{
	Snake *ptrSnake = malloc(sizeof(Snake));

	ptrSnake->ptrHead = malloc(sizeof(SnakePiece));
	ptrSnake->ptrHead->point = point;
	ptrSnake->ptrHead->ptrNext = NULL;
	
	ptrSnake->iPiecesToDraw = 3;
	ptrSnake->eCurrentDirection = EAST;
	ptrSnake->cSnakeChar = cSnakeChar;

	return ptrSnake;
}

int getSnakeLength(Snake *ptrSnake)
{
	SnakePiece *thru = ptrSnake->ptrHead;
	int iLength = 0;

	while (thru != NULL)
	{
		iLength++;
		thru = thru->ptrNext;
	}

	return iLength;
}

void removeOneSnakePiece(Snake *ptrSnake)
{
	SnakePiece *thru = ptrSnake->ptrHead;

	while (thru->ptrNext->ptrNext != NULL)
		thru = thru->ptrNext;

	gotoPoint(thru->ptrNext->point);
	printf(" ");

	free(thru->ptrNext);
	thru->ptrNext = NULL;
}

void addOneSnakePiece(Snake *ptrSnake, Point objPoint)
{
	SnakePiece *objSnakePiece = malloc(sizeof(SnakePiece));
	objSnakePiece->ptrNext = ptrSnake->ptrHead;
	objSnakePiece->point = objPoint;
	ptrSnake->ptrHead = objSnakePiece;

	gotoPoint(objPoint);
	printf("%c", ptrSnake->cSnakeChar);
}

bool advanceSnake(Snake *ptrSnake)
{
	Point objNextPoint;
	

	switch (ptrSnake->eCurrentDirection)
	{
		case NORTH:
			objNextPoint = makePoint(ptrSnake->ptrHead->point.x, ptrSnake->ptrHead->point.y - 1);
			break;

		case EAST:
			objNextPoint = makePoint(ptrSnake->ptrHead->point.x + 1, ptrSnake->ptrHead->point.y);
			break;

		case SOUTH:
			objNextPoint = makePoint(ptrSnake->ptrHead->point.x, ptrSnake->ptrHead->point.y + 1);
			break;

		case WEST:
			objNextPoint = makePoint(ptrSnake->ptrHead->point.x - 1, ptrSnake->ptrHead->point.y);
			break;
	}

	/* Advance local snake by adding one piece to the head of the snake */
	addOneSnakePiece(ptrSnake, objNextPoint);

	/*
	   [TASK #2]

	   Send a packet notifying all other snake game clients that you have added another
	   piece to your snake. This should be done by sending the following packet:

	      /---------------------------------------------------------------\
		  |  0x02  |  X location of new piece  | Y location of new piece  |
		  |        |     (as byte value)       |     (as byte value)      |
		  \---------------------------------------------------------------/
		  0        1                           2                          3

       For example, if the new piece of food is being added at (12, 14), the packet would
	   read as follows:

	         0x02     0x0c     0x0e     (in hex)
		        2       12       14     (in decmal)
		 00000010 00001100 00001110     (in binary)

       Once you have prepared the packet, send it to your broadcastMessage(...) function
	   you created in [TASK #1].
	*/
    char packet [ 3 ];
    packet [ 0 ] = 2;
    packet [ 1 ] = objNextPoint.x;
    packet [ 2 ] = objNextPoint.y;
    broadcastMessage (( void * ) packet, 3 );

	/*
	   Finish [TASK #2] between the [TASK #2] description and this comment.
	*/

	// Food Check
	if (memcmp(&objNextPoint, &objFoodPoint, sizeof(Point)) == 0)
	{
		ptrSnake->iPiecesToDraw += 4;
		placeNewFood();

		/*
		   [TASK #3]

		   Much like [TASK #2], but now you need to send another packet. This packet tells
		   other clients that the food has been moved. The contents of this packet should
		   be:

	         /-------------------------------------------------------------\
		     |  0x03  |  X location of new food  | Y location of new food  |
		     |        |     (as byte value)      |     (as byte value)     |
		     \-------------------------------------------------------------/
		     0        1                          2                         3

		   After calling placeNewFood(), the food location is updated in objFoodPoint
		*/

      packet [ 0 ] = 3;
      packet [ 1 ] = objFoodPoint.x;
      packet [ 3 ] = objFoodPoint.y;
      broadcastMessage (( void * ) packet, 3 );

		/*
		   Finish [TASK #3] between the [TASK #3] description and this comment.
		*/
	}

	if (ptrSnake->iPiecesToDraw == 0)
	{
		removeOneSnakePiece(ptrSnake);

		/*
		   [TASK #4]

		   Send the following packet:

	         /----------------------------------------\
		     |  0x01  |  Current length of the snake  |
		     |        |        (as byte value)        |
		     \----------------------------------------/
		     0        1                               5

		   Note that the length of the snake is four bytes now, not just a single byte
		   as it has been in [TASK #2] and [TASK #3]. We have provided a function
		   for you to get the current snake's length. This function is:

		      int getSnakeLength(Snake* ptrSnake);

		   and can be used in-line by the following line of code:

		      int snakelen = getSnakeLength(ptrSnake);
		*/

         int snakelen = getSnakeLength ( ptrSnake );
         char *temp = &snakelen;
         char length [ 5 ];
         length [ 0 ] = 1;
         length [ 1 ] = temp [ 0 ];
         length [ 2 ] = temp [ 1 ];
         length [ 3 ] = temp [ 2 ];
         length [ 4 ] = temp [ 3 ];
         broadcastMessage (( void * ) length, 5 );


		/*
		   Finish [TASK #4] between the [TASK #4] description and this comment.
		*/

	}
	else
		ptrSnake->iPiecesToDraw--;

	// Check the local snake to see if it died due to running into a wall...
	if (objNextPoint.x == 1 || objNextPoint.x == 80 || objNextPoint.y == 1 || objNextPoint.y == 22)
		return false;

	// Check the local snake to see if it has ran into itself or another snake...
	SnakeCollection *thruSnakes = objSnakeCollection;

	while (thruSnakes != NULL)
	{
		SnakePiece *thru = thruSnakes->ptrSnake->ptrHead;

		if (thruSnakes->ptrSnake == ptrSnake)
			thru = thru->ptrNext;

		while (thru != NULL)
		{
			if (memcmp(&(thru->point), &objNextPoint, sizeof(Point)) == 0)
				return false;

			thru = thru->ptrNext;
		}

		thruSnakes = thruSnakes->ptrNext;
	}

	// Update the direction we have just allowed the snake to travel in....
	ptrSnake->ePreviousDirectionMoved = ptrSnake->eCurrentDirection;

	fflush(stdout);
	return true;
}

void placeNewFood()
{
	objFoodPoint = makePoint((rand() % 78) + 2, (rand() % 20) + 2);
	drawFood();
}
